var Preloader = new Class({

	initialize: function() {
		this._currentlyLoading = '';
		this._loading = false;
		this._imgQueue = [];
		this._loadEvents = {};
		this._loadedImages = {};
	},

	addToQueue: function(src) {
		if (this.isLoaded(src) || this.isInQueue(src)) return;
		this._imgQueue.push(src);
		if (!this._loading) this._loadNext();
		return this;
	},

	addToFrontOfQueue: function(src) {
		if (this.isLoaded(src)) return false;
		if (this._currentlyLoading == src) return true;
		this.removeFromQueue(src);
		this._imgQueue.unshift(src);
		if (!this._loading) this._loadNext();
		return true;
	},

	removeFromQueue: function(src) {
		this._imgQueue.remove(src)
		return this;
	},

	addEventOnLoad: function(src, fn) {
		this._loadEvents[src] = fn;
		return this;
	},

	flushQueue: function() {
		this._imgQueue = [];
		return this;
	},

	stopAllEvents: function() {
		this._loadEvents = {};
		return this;
	},

	isLoaded: function(src) {
		return !!this._loadedImages[src];
	},

	isInQueue: function(src) {
		return (this._currentlyLoading == src || this._imgQueue.contains(src));
	},

	priorityLoadWithCallback: function(src, fn) {
		this.addEventOnLoad(src, fn);
		if (!this.addToFrontOfQueue(src)){
			this._fireLoadEvent(src); // Already loaded
			return true;
		}
		return false;
	},

	_fireLoadEvent: function(src) {
		if (this._loadEvents[src]) this._loadEvents[src].call(this._loadedImages[src]);
		this._loadEvents[src] = null;
	},

	_loadNext: function() {
		if (this._imgQueue.length == 0) {
			this._currentlyLoading = '';
			return this._loading = false;
		}
		this._loading = true;
		this._currentlyLoading = this._imgQueue.shift();
		var img = new Element('img');
		var preloader = this;
		img.addEvent('load', function() {
			preloader._loadedImages[this.src] = this;
			preloader._currentlyLoading = '';
			preloader._fireLoadEvent(this.src);
			setTimeout(function() {
				preloader._loadNext();
			}, 0); //setTimeout for Opera; stops this hogging the javascript thread.
			this.removeEvent('load', arguments.callee);
		});
		img.src = this._currentlyLoading;
	}

});